-- 将 "looper_custom_time" 脚本文件复制到 C:\Program Files (x86)\VideoLAN\VLC\lua\intf 文件夹中
-- 激活它：
-- vlc --extraintf=luaintf{intf="time_display"} -vv
-- -vv 方便调试 vlc菜单 Tools(工具)->Messages(消息)打开能看到调试消息
-- 修改vlc快捷图标目标设置为"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe" --extraintf=luaintf{intf="time_display"} -vv

-- 读取的文件
-- 00:21:58 开始修改音频输出方法的代码
-- 00:22:48 找到最小的期望音频延迟
-- 00:27:31 使用量纲分析转换为秒
-- 00:31:34 根据音频延迟写入声音
-- 00:34:14 关于在早期阶段保持代码灵活且稍微混乱的精彩旁白
-- 00:37:00 确定音频写入的位置
-- 00:46:27 如何处理低延迟场景

-- 读到的内容
-- time = 00:21:58, message = 开始修改音频输出方法的代码
-- time = 00:22:48, message = 找到最小的期望音频延迟
-- time = 00:27:31, message = 使用量纲分析转换为秒
-- time = 00:31:34, message = 根据音频延迟写入声音
-- time = 00:34:14, message = 关于在早期阶段保持代码灵活且稍微混乱的精彩旁白
-- time = 00:37:00, message = 确定音频写入的位置
-- time = 00:46:27, message = 如何处理低延迟场景
-- -- 定义目标时间点（hh:mm:ss 格式）及对应消息
-- local targetMessages = {
-- time = 00:21:58, message = 开始修改音频输出方法的代码
-- time = 00:22:48, message = 找到最小的期望音频延迟
-- time = 00:27:31, message = 使用量纲分析转换为秒
-- time = 00:31:34, message = 根据音频延迟写入声音
-- time = 00:34:14, message = 关于在早期阶段保持代码灵活且稍微混乱的精彩旁白
-- time = 00:37:00, message = 确定音频写入的位置
-- time = 00:46:27, message = 如何处理低延迟场景
-- }


function SafeOsdMessage(text, position, duration)
   local vout = vlc.object.vout()
   if vout then
      vlc.osd.message(text, vlc.osd.channel_register(), position or "top-left", duration or 1000000)
   else
      Log("OSD skipped: no vout")
   end
end

-- 单独的函数，打印 targetMessages 表的内容
function printTargetMessages(targetMessages)
   Log("Loaded target messages:")
   for _, target in ipairs(targetMessages) do
      Log("time = " .. target.time .. ", message = " .. target.message)
   end
end

-- 读取文件并解析目标时间和操作
-- 调试输出路径和文件打开情况
function loadTargetMessages(filePath)
   -- 里面不能打印log 不然会有问题
   local targetMessages = {}
   local file = io.open(filePath, "r")
   if file then
      -- Log("File opened successfully")
      for line in file:lines() do
         local time, message = line:match("^(%d+:%d+:%d+)%s*(.*)$")
         if time and message then
            -- 按照时间字符串解析操作
            table.insert(targetMessages, { time = time, message = message })
         else
         end
      end
      file:close()
   else
   end
   return targetMessages
end

-- 用于记录已触发的目标时间
-- 文件路径修改成之间的路径
local targetMessages = loadTargetMessages("C:/Users/16956/Documents/game/day292/game/Q&A.md")
local triggeredTargets = {}

function Looper()
   local loops = 0 -- counter of loops
   -- 加载目标时间和操作
   while true do
      -- 调试打印读取的文件的内容 打开后台打印的数据太多
      -- printTargetMessages(targetMessages)
      if vlc.volume.get() == -256 then break end -- inspired by syncplay.lua; kills vlc.exe process in Task Manager

      if vlc.playlist.status() == "stopped" then -- no input or stopped input
         loops = loops + 1
         Log(loops)
         Sleep(1)
      else                                   -- playing, paused
         if vlc.playlist.status() == "playing" then
            local input = vlc.object.input() -- 获取当前播放的输入对象
            vlc.var.set(input, "rate", 1.5)  -- 设置播放速率
            showFinalTime()
            checkTargetMessages()
            Sleep(0.1)
         elseif vlc.playlist.status() == "paused" then
            showFinalTime()
            Sleep(0.3)
         else -- unknown status
            Log("unknown")
            Sleep(1)
         end
      end
   end
end

-- 将 hh:mm:ss 格式的时间字符串转换为秒数
function parseTime(timeStr)
   local hours, minutes, seconds = timeStr:match("^(%d+):(%d+):(%d+)$")
   hours = tonumber(hours) or 0
   minutes = tonumber(minutes) or 0
   seconds = tonumber(seconds) or 0
   return hours * 3600 + minutes * 60 + seconds
end

local lastTarget = nil
local lastTimePassed = nil
local currentMessage = nil
local pause = true
-- 检查目标时间并显示相关消息
function checkTargetMessages()
   local timePassed = math.floor(getTimePassed()) -- 获取当前时间（秒）
   -- Log("checkTargetMessages")
   local closestTarget = nil
   local closestDifference = math.huge                           -- 初始化一个非常大的值作为最接近的时间差
   for _, target in ipairs(targetMessages) do
      local targetSeconds = parseTime(target.time) * 1000 * 1000 -- 将 hh:mm:ss 转为秒

      -- 确保目标时间小于或等于当前时间
      if targetSeconds <= timePassed then
         local difference = timePassed - targetSeconds -- 计算当前时间与目标时间的差值

         -- 找到最接近的目标时间
         if difference < closestDifference then
            closestTarget = target
            closestDifference = difference
            currentMessage = closestTarget.message
         end
      end
   end

   if closestTarget == lastTarget and closestTarget ~= nil and absoluteDifference(timePassed, lastTimePassed) > 5 * 1000 * 1000 then
      Log("diff" .. absoluteDifference(timePassed, lastTimePassed))
      triggeredTargets[closestTarget.time] = false
      pause = false
   end

   -- 如果找到了最接近的目标时间，显示消息
   if closestTarget and not triggeredTargets[closestTarget.time] then
      -- 显示最接近的消息

      local vout = vlc.object.vout()
      if vout then
         vlc.osd.message(closestTarget.message, vlc.osd.channel_register(), "top-left", 1000000)
      else
         Log("No vout object, cannot display OSD.")
      end
      if pause then
         vlc.playlist.pause()
      end
      pause = true

      -- 标记该时间点已触发
      triggeredTargets[closestTarget.time] = true
      Log("lastTarget ~= nil before")
      if lastTarget ~= nil and lastTarget ~= closestTarget then
         Log("lastTarget ~= nil == true")
         triggeredTargets[lastTarget.time] = false
      end
      lastTarget = closestTarget;
   end
   lastTimePassed = timePassed;
end

function absoluteDifference(x, y)
   if x > y then
      return x - y
   else
      return y - x
   end
end

function Log(lm)
   vlc.msg.info("[looper_intf] " .. lm)
end

function showFinalTime()
   Log("showFinalTime")
   local timePassed = getTimePassed()
   local formattedTime = formatTime(timePassed)
   Log(formattedTime)
   -- vlc.osd.message("Current Time: " .. formattedTime, vlc.osd.channel_register(), "top-right", 1200000)
   local vout = vlc.object.vout()
   if vout then
      vlc.osd.message((currentMessage ~= nil) and currentMessage or "", vlc.osd.channel_register(), "top-left", 1000000)
   else
      Log("No vout object, cannot display OSD.")
   end
end

-- 将相对时间（秒）转换为时:分:秒格式
function formatTime(microseconds)
   local seconds = math.floor(microseconds / (1000 * 1000))
   local hours = math.floor(seconds / 3600)
   local minutes = math.floor((seconds % 3600) / 60)
   local secs = seconds % 60
   return string.format("%02d:%02d:%02d", hours, minutes, secs)
end

function getTimePassed()
   local input = vlc.object.input()
   if input then
      local time = vlc.var.get(input, "time") or 0
      Log("Raw Time Passed: " .. time)
      return time -- 此处保留毫秒
   else
      return 0
   end
end

function Sleep(st) -- seconds
   vlc.misc.mwait(vlc.misc.mdate() + st * 1000000)
end

Looper()
